//=================================================
// nabton.ino
// 2015-01-18
// Version 0.2
//=================================================
//
// D0 RX used for serial communication to server (Raspberry Pi)
// D1 TX used for serial communication to server (Raspberry Pi)
// D2
// D3 Message Pin (blink led)
// D4 IR Data
// D5
// D6 DIR Stepper
// D7 STEP Stepper
// D8 SLEEP Stepper
// D9 One Wire Data
// D10  RX Bluetooth device
// D11  TX Bluetooth device
// D12 
// D13
//
// A0
// A1
// A2
// A3
// A4 SDA I2C OLED
// A5 SCL I2C OLED

// MEGA
// D20 SDA I2C OLED
// D21 SCL I2C OLED
//=================================================
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SoftwareSerial.h>
//#include <IRremote.h>
#include <U8glib.h>
//**************************************************
// Definitions and Parameters
//**************************************************
     unsigned long ttemp;
//=================================================
// IR
//=================================================
int IR_PIN = 4;
//IRrecv irrecv(IR_PIN);
//decode_results results;

//=================================================
// One Wire
//=================================================
#define ONE_WIRE_BUS 9
#define TEMPERATURE_PRECISION 12
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress device[10];
int nsensors = 0;
//=================================================
// Bluetooth
//=================================================
#define BRX 10
#define BTX 11
SoftwareSerial btSerial(BRX,BTX); // RX, TX

//==================================================
// Stepper Motor
//==================================================
int DIR   = 6; 
int STEP  = 7;
int SLEEP = 8;
#define MAX_SID 6
//==================================================
// OLED I2C
//==================================================

//U8GLIB_SSD1306_128X64 u8g(13, 11, 10, 9);// SW SPI protocol(4 pins): SCK = 13, MOSI = 11, CS = 10, A0 = 9	
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); // Small display I2C protocol (2 pins)
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE); // Large display
char dl[5][8],dm[5][8],dr[5][8];
//==================================================
// Misc
//==================================================
#define PIN_MSG 3
#define NABTON_DATA 1
#define NABTON_DATA_ACK 2

// Arduino Control Protocol
#define ON_HB_VAL        2
#define ON_HB_UNIT       3
#define ON_STEPPER_DIR   4
#define ON_STEPPER_STEPS 5
#define ON_STEPPER_SPEED 6

int nabton_hb = 2;
int nabton_hb_unit = 10; // 10=sec
int nabton_sid = 0;
int msg[100];
int on[100];
int value[100];
int sid[MAX_SID];
int sidHb[MAX_SID];
int sidHbUnit[MAX_SID];
int sidDelay[MAX_SID]; // Always in sec
int sidCountDown[MAX_SID];
//**************************************************
// Function Library
//**************************************************


//=================================================
void sendNDS(int sid, float data)
//=================================================
{
  //Serial.print(":"); //start
  Serial.print(NABTON_DATA);
  Serial.print(" "); 
  Serial.print(sid);
  Serial.print(" "); 
  Serial.print(data);
  Serial.print(";"); // End
  Serial.flush();
}
//=================================================
void blinkLed(int nn)
//=================================================
{
  digitalWrite(PIN_MSG,LOW);
  for(int i=0;i<nn;i++)
  { 
     digitalWrite(PIN_MSG,HIGH);
     delay(100);
     digitalWrite(PIN_MSG,LOW);
     delay(100);
  }  
}
//================================================
void stepCW(int steps,int dd)
//================================================
{
  int i;
  digitalWrite(DIR, LOW);   
  digitalWrite(SLEEP, HIGH); // Set the Sleep mode to AWAKE.
  for(i=0;i<=steps;i++)
    {
      delayMicroseconds(200);
      digitalWrite(STEP, HIGH); 
      //delay(dd);      
      digitalWrite(STEP, LOW);
      delay(dd);  
    }  
  digitalWrite(DIR, LOW);   
  digitalWrite(SLEEP, LOW); // Set the Sleep mode to SLEEP.   
}

//================================================
void stepCCW(int steps,int dd)
//================================================
{
  int i;
  digitalWrite(DIR, HIGH);                 
  digitalWrite(SLEEP, HIGH); // Set the Sleep mode to AWAKE.
  for(i=0;i<=steps;i++)
    {
      delayMicroseconds(200);
      digitalWrite(STEP, HIGH);   
      //delay(dd);       
      digitalWrite(STEP, LOW); 
      delay(dd);     
    }  
  digitalWrite(DIR, LOW);   
  digitalWrite(SLEEP, LOW); // Set the Sleep mode to SLEEP.    
}

//=================================================
void draw()
//=================================================
{
  // Horizontal pixels: 0 - 120
  // Vertical pixels: 0 - 63
  //u8g.setFont(u8g_font_6x10);
  u8g.setFont(u8g_font_unifont);
  //u8g.setFont(u8g_font_osb21);
  /*u8g.drawStr( 0, 1, ".....");
  u8g.drawStr( 45, 1, ".....");
  u8g.drawStr( 90, 1, ".....");
  
  u8g.drawStr( 0, 63, "_____");
  u8g.drawStr( 45,63, "_____");
  u8g.drawStr( 90,63, "_____");*/
  
  u8g.drawStr( 0, 10, dl[1]);
  u8g.drawStr( 0, 27, dl[2]);
  u8g.drawStr( 0, 45, dl[3]);
  u8g.drawStr( 0, 62, dl[4]);

  u8g.drawStr( 45, 10, dm[1]);
  u8g.drawStr( 45, 27, dm[2]);
  u8g.drawStr( 45, 45, dm[3]);
  u8g.drawStr( 45, 62, dm[4]);

  u8g.drawStr( 90, 10, dr[1]);
  u8g.drawStr( 90, 27, dr[2]);
  u8g.drawStr( 90, 45, dr[3]);
  u8g.drawStr( 90, 62, dr[4]);  

}

//=================================================
//=================================================
void setup()
//=================================================
//=================================================
{
  int i,unit;
  String strr;
  Serial.begin(9600);
  
  pinMode(DIR, OUTPUT);
  pinMode(STEP, OUTPUT);
  pinMode(SLEEP, OUTPUT);
  
  pinMode(IR_PIN, INPUT);
  //pinMode(ONE_WIRE_BUS, INPUT);
  
  pinMode(PIN_MSG, OUTPUT);
  digitalWrite(PIN_MSG,LOW);

// OLED
//=================================================

  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }
  strcpy(dr[2],"v0.2");
  u8g.firstPage();  
  do {
        draw();
  } while( u8g.nextPage() ); 
  delay(1000);  

// One Wire
//=================================================

  sensors.begin();
  nsensors = sensors.getDeviceCount();
  if(nsensors > 0)
  {
    for(i=0;i<nsensors;i++)
    {
      sensors.getAddress(device[i], i);
      sensors.setResolution(device[i], TEMPERATURE_PRECISION);
    }
  }



// General
//=================================================  

  u8g.firstPage();  
  do {
        draw();
  } while( u8g.nextPage() ); 
  delay(1000);  
  
  for(int j=0;j<10;j++)msg[j] = 0;
  
  if(nabton_hb_unit == 1) unit = 1; // sec
  if(nabton_hb_unit == 2) unit = 60; //minute
  if(nabton_hb_unit == 3) unit = 60*60; // hour
  if(nabton_hb_unit == 4) unit = 24*60*60; //24h
  ttemp = nabton_hb*unit;
  if(ttemp > 4000000000) ttemp = 4000000000;                

  sid[1] = 91;
  sid[2] = 92;
  sid[3] = 93;
  sid[4] = 94;
 
  
  sidDelay[1] = 11;
  sidDelay[2] = 12;
  sidDelay[3] = 13;
  sidDelay[4] = 14;
}


//=================================================
void recACK()
//=================================================
{
     int i,k,ndata,unit,indexSid,sidGeneric,change;
     float tempC;
     char buffer[50];
     String str;

     blinkLed(1);
     int nx = Serial.available();

     for(i=0;i<100;i++)on[i] = 0;
// Message received
//------------------------------------
  if (nx > 0) 
  {
     Serial.readBytes(buffer,nx);
     for(i=0;i<nx;i++)
     {
       msg[i] = (int)buffer[i]; 
     }
     str = String(nx);
     str.toCharArray(dr[1],8); 
       
     if(msg[0] == NABTON_DATA_ACK)
     {
       nabton_sid = msg[1] + msg[2]*256;
       str = String(nabton_sid);
       str.toCharArray(dr[3],8); 
       indexSid = 0;
       for(i=1;i<MAX_SID;i++)
       {
        if(sid[i] == nabton_sid) indexSid = i; 
       }
       // sid exists!
       if(indexSid != 0)
       {
         k = 3;
         while(msg[k] != 0)
         {
           on[msg[k]] = 1;
           value[msg[k]] = msg[k+1];
           k = k + 2;
         }
         k = k-1;
         
         change =0;
         if(on[ON_HB_VAL] == 1)
         { 
           sidHb[indexSid]     = value[ON_HB_VAL];
           change = 1;
         }
         if(on[ON_HB_UNIT] == 1)
         {
           sidHbUnit[indexSid] = value[ON_HB_UNIT];
           change = 1;
         }
         if(change == 1)
         {
           if(sidHbUnit[indexSid] == 1) unit = 1; // sec
           if(sidHbUnit[indexSid] == 2) unit = 60; //minute
           if(sidHbUnit[indexSid] == 3) unit = 60*60; // hour
           if(sidHbUnit[indexSid] == 4) unit = 24*60*60; //24h
           ttemp = sidHb[indexSid]*unit;
           if(ttemp > 4000000000) ttemp = 4000000000;       
           sidDelay[indexSid] = ttemp;  
           sidCountDown[indexSid] = ttemp;
         }
       } else
       {
          strcpy(dr[2],"E-01");
       }    

         if(on[ON_STEPPER_DIR] == 1 && on[ON_STEPPER_STEPS] == 1)
         {
 
           int dir   = value[ON_STEPPER_DIR];
           int steps = value[ON_STEPPER_STEPS];
           int stepper_speed = value[ON_STEPPER_SPEED];
           str = String(steps);
           str.toCharArray(dm[4],8); 
           if(dir==1)strcpy(dr[4],"STP>");
           if(dir==2)strcpy(dr[4],"STP<");
           
           u8g.firstPage();  
           do {
             draw();
           } while( u8g.nextPage() ); 
           
           steps = steps*10;
           if(steps > 0 || steps < 1000)
           {
             if(dir == 1) stepCW(steps,stepper_speed);
             if(dir == 2) stepCCW(steps,stepper_speed);
           }
         } 
         
           strcpy(dr[4],"ACK");
           u8g.firstPage();  
           do {
             draw();
           } while( u8g.nextPage() );       
     } 
     else
     {
       strcpy(dr[4],"?");
     }

  }
  else
       strcpy(dr[4],"off");
}
void loop()
//=================================================
//=================================================
{
int i;
float tempC;
String str;

  sensors.requestTemperatures();
  for(i=1;i<=nsensors;i++)
  {
    tempC = sensors.getTempC(device[i-1]);       
    str = String(tempC);
    str.toCharArray(dl[i],8); 
    str = String(sidCountDown[i]);
    str.toCharArray(dm[i],8); 
    if(sidCountDown[i]==0)
    {
      sendNDS(sid[i],tempC);
      recACK();
      sidCountDown[i] = sidDelay[i];
    }
    else
     sidCountDown[i]--;

  u8g.firstPage();  
  do {
        draw();
  } while( u8g.nextPage() ); 
  
  }
  delay(1000);
}
